////
////  LocationManager2.swift
////  LocationDemo
////
////  Created by HzS on 2023/2/1.
////
//
//import UIKit
//import CoreLocation
//import CoreMotion
//
///// 整体思路是app运行时，1、获取一次定位，将获取的定位当作圆心，并设置半径形成地理围栏。2、离开这个围栏时触发回调，然后开始步骤1
//
//class LocationManager3: NSObject {
//    
//    static let didChangeAuthorizationNotification = Notification.Name("LocationManagerDidChangeAuthorizationNotification")
//    
//    static let shared: LocationManager3 = LocationManager3()
//    
//    let database = Database()
//    var currentAuthorizationStatus: CLAuthorizationStatus {
//        if #available(iOS 14.0, *) {
//            return locationManager.authorizationStatus
//        } else {
//            return CLLocationManager.authorizationStatus()
//        }
//    }
//    
//    private var region: CLCircularRegion?
//    @UserDefaultCustom(key: "kLastOriginLoccation", defaultValue: nil)
//    private var lastOriginLoccation: LocationModel? // 最近一个火星坐标点
//    private lazy var locationManager: CLLocationManager = {
//        let manager = CLLocationManager()
//        // 获取定位的精度要求（对startMonitoringSignificantLocationChanges无效）
//        manager.desiredAccuracy = kCLLocationAccuracyBest
//        // 持续定位时用户移动多远距离，才进行定位更新（对startMonitoringSignificantLocationChanges无效）
//        manager.distanceFilter = 50
//        // 允许后台运行
//        manager.allowsBackgroundLocationUpdates = true
//        manager.delegate = self
//        return manager
//    }()
//    
//    private let activityManager: CMMotionActivityManager = {
//        let manager = CMMotionActivityManager()
//        // 第一次时申请权限
//        if CMMotionActivityManager.isActivityAvailable() && CMMotionActivityManager.authorizationStatus() == .notDetermined {
//            manager.startActivityUpdates(to: .main) { _ in
//            }
//        }
//        return manager
//    }()
//    
//    private(set) var lastAuthorizationStatus: CLAuthorizationStatus = .notDetermined
//    private var isUpdatingLocation: Bool = false
//    
//    private var waitingTaskIdentifier: UIBackgroundTaskIdentifier?
//    private var waitingTimer: PoTimer?
//    private var waitingLocations: [CLLocation] = []
//    
//    private var regionTimer: PoTimer?
//    private var isUpdateFromRegionTimer: Bool = false
//    
//    override init() {
//        super.init()
//        
//        lastAuthorizationStatus = currentAuthorizationStatus
//        
//        NotificationCenter.default.addObserver(forName: UIApplication.willEnterForegroundNotification, object: nil, queue: nil) { _ in
//            LogManager.shared.log("app willEnterForeground\n")
//        }
//        
//        NotificationCenter.default.addObserver(forName: UIApplication.willResignActiveNotification, object: nil, queue: nil) { [weak self] _ in
//            LogManager.shared.log("app willResignActive\n")
//            
//            if UIApplication.shared.applicationState != .background { return }
//            // 创建一个小围栏
//            if let lastOriginLoccation = self?.lastOriginLoccation {
//                self?.stopUpdatingLocation()
//                self?.startMonitoringRegion(center: CLLocationCoordinate2D(latitude: lastOriginLoccation.latitude, longitude: lastOriginLoccation.longitude), radius: 15)
//                LogManager.shared.log("willTerminateNotification：创建一个小围栏\n")
//            } else {
//                LogManager.shared.log("willTerminateNotification：当前没有建围栏\n")
//            }
//        }
//        
//        NotificationCenter.default.addObserver(forName: UIApplication.didBecomeActiveNotification, object: nil, queue: nil) { [weak self] _ in
//            LogManager.shared.log("app didBecomeActive\n")
//            if UIApplication.shared.applicationState != .background { return }
//            self?.startLocationServices()
//        }
//        
//        NotificationCenter.default.addObserver(forName: UIApplication.didEnterBackgroundNotification, object: nil, queue: nil) { _ in
//            LogManager.shared.log("app didEnterBackground\n")
//        }
//        
//        NotificationCenter.default.addObserver(forName: UIApplication.willTerminateNotification, object: nil, queue: nil) { [weak self] _ in
//            LogManager.shared.log("app willTerminate\n")
//            // 创建一个小围栏
//            if let lastOriginLoccation = self?.lastOriginLoccation {
//                self?.stopUpdatingLocation()
//                self?.startMonitoringRegion(center: CLLocationCoordinate2D(latitude: lastOriginLoccation.latitude, longitude: lastOriginLoccation.longitude), radius: 15)
//                LogManager.shared.log("willTerminateNotification：创建一个小围栏\n")
//            } else {
//                LogManager.shared.log("willTerminateNotification：当前没有建围栏\n")
//            }
//        }
//    }
//    
//    func startLocationServices() {
//        // 开启持续定位
//        startUpdatingLocation()
//        // 开启重要位置变化定位（可后台唤醒，要移动比较远的距离后才会触发位置更新）
//        locationManager.startMonitoringSignificantLocationChanges()
//    }
//    
//    func stopLocationServices() {
//        stopUpdatingLocation()
//        locationManager.stopMonitoringSignificantLocationChanges()
//        stopMonitoringAllRegions()
//    }
//    
//    func checkAndRequestAuthorization() -> Bool {
//        if (CLLocationManager.authorizationStatus() == .denied || CLLocationManager.authorizationStatus() == .notDetermined) {
//            // 没有获取到权限，再次请求授权
//            locationManager.requestWhenInUseAuthorization()
//        } else if CLLocationManager.authorizationStatus() == .authorizedWhenInUse {
//            locationManager.requestAlwaysAuthorization()
//        } else if CLLocationManager.authorizationStatus() == .authorizedAlways {
//            return true
//        }
//        return false
//    }
//    
//    private func startUpdatingLocation(_ isForce: Bool = false) {
//        LogManager.shared.log("startUpdatingLocation\n")
//        if isUpdatingLocation && !isForce { return }
//        isUpdatingLocation = true
//        // 强制发起定位（当前开着的话再调用不会发生任何事，必须关后再打开）
//        if isForce { locationManager.stopUpdatingLocation() }
//        locationManager.startUpdatingLocation()
//    }
//    
//    private func stopUpdatingLocation() {
//        isUpdatingLocation = false
//        locationManager.stopUpdatingLocation()
//        LogManager.shared.log("stopUpdatingLocation\n")
//    }
//    
//    private func startWaitingTimer() {
//        // 因为延迟3秒后再处理，防止被系统干掉，申请更多的处理时间
//        beginWaitingBackgroundTask()
//        
//        waitingTimer?.invalidate()
//        waitingTimer = PoTimer(fireTime: 3, timeInterval: 0, target: self, selector: #selector(handleWaitingTimerEvent), repeats: false)
//    }
//    
//    private func cancelWaitingTimer() {
//        waitingTimer?.invalidate()
//        waitingTimer = nil
//    }
//    
//    /// 120秒后检查是否已经创建围栏，否则创建一个
//    private func startRegionTimer() {
//        regionTimer?.invalidate()
//        regionTimer = PoTimer(fireTime: 120, timeInterval: 0, target: self, selector: #selector(handleRegionTimerEvent), repeats: false)
//        isUpdateFromRegionTimer = false
//    }
//    
//    private func cancelRegionTimer() {
//        isUpdateFromRegionTimer = false
//        regionTimer?.invalidate()
//        regionTimer = nil
//    }
//    
//    @objc
//    private func handleRegionTimerEvent() {
//        isUpdateFromRegionTimer = true
//        LogManager.shared.log("围栏定时器回调：发起一次位置更新\n")
//        startUpdatingLocation(true)
//    }
//    
//    // MARK: - BackgroundTask
//    
//    private func beginWaitingBackgroundTask() {
//        if let waitingTaskIdentifier {
//            UIApplication.shared.endBackgroundTask(waitingTaskIdentifier)
//        }
//        waitingTaskIdentifier = UIApplication.shared.beginBackgroundTask(expirationHandler: { [weak self] in
//            if let waitingTaskIdentifier = self?.waitingTaskIdentifier {
//                UIApplication.shared.endBackgroundTask(waitingTaskIdentifier)
//            }
//            self?.waitingTaskIdentifier = nil
//        })
//    }
//    
//    private func endWaitingBackgroundTask() {
//        if let waitingTaskIdentifier {
//            UIApplication.shared.endBackgroundTask(waitingTaskIdentifier)
//        }
//        self.waitingTaskIdentifier = nil
//    }
//    
//    private func logFilterLocation(locations: [CLLocation], findLocation: CLLocation) {
//        guard let last = lastOriginLoccation?.toCLLocation else { return }
//        for location in locations {
//            if findLocation.timestamp != location.timestamp {
//                LogManager.shared.log("过滤的点距离：\(location.distance(from: last)) 精度: \(location.horizontalAccuracy)\n")
//            }
//        }
//        LogManager.shared.log("找到的点距离：\(findLocation.distance(from: last)) 精度: \(findLocation.horizontalAccuracy)\n")
//    }
//    
//    @objc
//    private func handleWaitingTimerEvent() {
//        LogManager.shared.log("\(#function)\n")
//        // 清理定时器
//        cancelWaitingTimer()
//        defer { self.endWaitingBackgroundTask() }
//        
//        // 从待处理点中找寻最优点
//        let location = findBestLocation(in: waitingLocations)
//        if let location { logFilterLocation(locations: waitingLocations, findLocation: location) }
//        waitingLocations.removeAll()
//        
//        let isUpdateFromRegionTimer = isUpdateFromRegionTimer
//        self.isUpdateFromRegionTimer = false
//        guard let location else { return }
//        
//        // 拿到上次最后的定位
//        let lastOriginLoccation = lastOriginLoccation?.toCLLocation
//        
//        // 是围栏定时器触发的更新
//        if isUpdateFromRegionTimer {
//            // 清理定时器
//            cancelRegionTimer()
//            
//            self.lastOriginLoccation = LocationModel(clLocation: location)
//            // 2分钟后还没移动10米，则认为已到目的地，暂停持续更新，创建围栏
//            if shouldFilterLocation(location) {
//                self.stopUpdatingLocation()
//                LogManager.shared.log("开启小围栏围栏\n")
//                startMonitoringRegion(center: location.coordinate, radius: 15)
//                return
//            }
//            // 反地理解码后获取到的是地球坐标
//            CLGeocoder().reverseGeocodeLocation(location, completionHandler: { (pms, err) -> Void in
//                guard let newLocation = pms?.last?.location else {
//                    LogManager.shared.log("反地理解码失败，重新定位\n")
//                    self.startUpdatingLocation(true)
//                    return
//                }
//                self.database.save(location: newLocation, horizontalAccuracy: location.horizontalAccuracy)
//                var address: String = ""
//                if let placemark = pms?.last {
//                    address = "\(placemark.locality ?? "")\(placemark.subLocality ?? "")\(placemark.name ?? "")"
//                }
//                self.logLocation(newLocation, address: address, originLocation: location, lastOriginLocation: lastOriginLoccation)
//            })
//        } else {
//            // 开启新的围栏创建计时器
//            startRegionTimer()
//            
//            if shouldFilterLocation(location) {
//                return
//            }
//            
//            // 检查用户的运动类型
//            calculateUserActivityAndAppropriateUpdateDistance(location: location, lastLocation: lastOriginLoccation) { activity, distance in
//                LogManager.shared.log("--- 用户运动状态:\(activity) 建议定位距离:\(Int(distance))\n")
//                self.locationManager.distanceFilter = distance
//                if self.shouldFilterLocation(location, by: activity) {
//                    // 被过滤了，开始新的定位
//                    self.locationManager.distanceFilter = 30
//                    return
//                }
//                
//                // 反地理解码后获取到的是地球坐标
//                CLGeocoder().reverseGeocodeLocation(location, completionHandler: { (pms, err) -> Void in
//                    guard let newLocation = pms?.last?.location else {
//                        LogManager.shared.log("反地理解码失败，重新定位\n")
//                        self.startUpdatingLocation(true)
//                        return
//                    }
//                    self.database.save(location: newLocation, horizontalAccuracy: location.horizontalAccuracy)
//                    var address: String = ""
//                    if let placemark = pms?.last {
//                        address = "\(placemark.locality ?? "")\(placemark.subLocality ?? "")\(placemark.name ?? "")"
//                    }
//                    self.logLocation(newLocation, address: address, originLocation: location, lastOriginLocation: lastOriginLoccation)
//                })
//            }
//        }
//
//    }
//    
//    private func findBestLocation(in locations: [CLLocation]) -> CLLocation? {
//        let locations = locations.filter({ $0.horizontalAccuracy >= 0 })
//        if locations.count <= 1 { return locations.first }
//        
//        // 筛选出精度小于100的
//        let accuracy150 = locations.filter({ $0.horizontalAccuracy < 100 })
//        // 如果只有一个，直接返回
//        if accuracy150.count == 1 { return accuracy150.first }
//        
//        // 精度小于100大于2个则在其中继续筛选，否则从原始数组继续筛选
//        let newLocations = accuracy150.count > 1 ? accuracy150 : locations
//        // 与上一个点的距离升序排序
//        if let lastOriginLoccation = lastOriginLoccation?.toCLLocation {
//            let sortedDistance = newLocations.sorted(by: { $0.distance(from: lastOriginLoccation) < $1.distance(from: lastOriginLoccation) })
//            if sortedDistance.count <= 2 { // 取最短
//                return sortedDistance.first
//            } else { // 取中位数
//                return sortedDistance[sortedDistance.count / 2]
//            }
//        } else { // 没有上一个点作为比较，则找一个精度最好的
//            return newLocations.min(by: { $0.horizontalAccuracy < $1.horizontalAccuracy })
//        }
//    }
//    
//    // MARK: - Private methods
//    
//    private func logLocation(_ location: CLLocation, address: String, originLocation: CLLocation, lastOriginLocation: CLLocation?) {
//        var distance: Double = 0
//        if let lastOriginLocation {
//            distance = originLocation.distance(from: lastOriginLocation)
//        }
//        LogManager.shared.log("location: [\(LogManager.shared.timeFormatter.string(from: originLocation.timestamp)), \(location.coordinate.latitude), \(location.coordinate.longitude), \(Int(originLocation.speed)), \(Int(originLocation.horizontalAccuracy)), \(Int(distance)), \(address)]\n\n")
//    }
//    
//    /// 开启地理围栏
//    private func startMonitoringRegion(center: CLLocationCoordinate2D, radius: CLLocationDistance) {
//        stopMonitoringAllRegions()
//        
//        region = CLCircularRegion(center: center, radius: radius, identifier: "UpdateCircle")
//        region?.notifyOnExit = true
//        locationManager.startMonitoring(for: region!)
//    }
//    
//    /// 移除已设置的地理围栏
//    private func stopMonitoringAllRegions() {
//        locationManager.monitoredRegions.forEach { region in
//            locationManager.stopMonitoring(for: region)
//        }
//        region = nil
//    }
//    
//    /// 根据点来过滤
//    private func shouldFilterLocation(_ location: CLLocation) -> Bool {
//        guard let lastOriginLoccation = lastOriginLoccation?.toCLLocation else {
//            return false
//        }
//        
//        let distance = location.distance(from: lastOriginLoccation)
//        if distance < 10 {
//            LogManager.shared.log("过滤原因：与上一个点距离 \(distance)m\n")
//            return true
//        }
//        
//        let timeInterval = location.timestamp.timeIntervalSince(lastOriginLoccation.timestamp)
//        if timeInterval < 2 {
//            LogManager.shared.log("过滤原因：与上一个点时间间隔 \(timeInterval)s\n")
////            return true
//        }
//        
//        let speed = distance / timeInterval
//        if speed > 98 { // 高铁最高时速
//            LogManager.shared.log("过滤原因：速度达到 \(speed)m/s\n")
////            return true
//        }
//        return false
//    }
//    
//    /// 根据点和用户行为来过滤
//    private func shouldFilterLocation(_ location: CLLocation, by userActivity: UserActivityType) -> Bool {
//        switch userActivity {
//        case .stationary, .walking:
//            if location.horizontalAccuracy > 100 {
//                return true
//            }
//        default:
//            break
//        }
//        self.lastOriginLoccation = LocationModel(clLocation: location)
//        return false
//    }
//}
//
//// MARK: - CLLocationManagerDelegate
//extension LocationManager3: CLLocationManagerDelegate {
//    
//    /// 定位更新，获取到的是火星坐标
//    func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
//        guard let location = locations.last else { return }
//        
//        waitingLocations.append(location)
//        if waitingTimer == nil { // 开启一个2秒后的回调
//            startWaitingTimer()
//        }
//    }
//    
//    /// 成功开启地理围栏
//    func locationManager(_ manager: CLLocationManager, didStartMonitoringFor region: CLRegion) {
//        LogManager.shared.log("成功开启地理围栏\n")
//    }
//    
//    /// 设置地理围栏后，出围栏的回调
//    func locationManager(_ manager: CLLocationManager, didExitRegion region: CLRegion) {
//        // 出围栏后我们再获取一次定位，然后建立新的围栏
//        LogManager.shared.log("走出地理围栏\n")
//    }
//    
//    /// 地理围栏状态改变
//    func locationManager(_ manager: CLLocationManager, didDetermineState state: CLRegionState, for region: CLRegion) {
//        LogManager.shared.log("地理围栏状态变化：\(state.rawValue)\n")
//        if state == .outside {
//            startUpdatingLocation()
//        }
//    }
//    
//    /// 地理围栏 监控失败
//    func locationManager(_ manager: CLLocationManager, monitoringDidFailFor region: CLRegion?, withError error: Error) {
//        LogManager.shared.log("++++ monitoringDidFail\(error.localizedDescription)\n")
//        DispatchQueue.main.asyncAfter(deadline: .now() + 5, execute: {
//            self.startUpdatingLocation()
//        })
//    }
//    
//    /// 当获取定位出错时调用
//    func locationManager(_ manager: CLLocationManager, didFailWithError error: Error) {
//        startUpdatingLocation()
//        LogManager.shared.log("++++ 定位错误：\(error.localizedDescription)\n")
//    }
//    
//    func locationManagerDidPauseLocationUpdates(_ manager: CLLocationManager) {
//        LogManager.shared.log("++++ 定位暂停了\n")
//    }
//
//    func locationManagerDidResumeLocationUpdates(_ manager: CLLocationManager) {
//        LogManager.shared.log("++++ 定位恢复了\n")
//    }
//    
//    /// 定位授权，每次app启动都会回调一次
//    @available(iOS 14.0, *)
//    func locationManagerDidChangeAuthorization(_ manager: CLLocationManager) {
//        let newStatus = manager.authorizationStatus
//        if newStatus != lastAuthorizationStatus {
//            NotificationCenter.default.post(name: LocationManager3.didChangeAuthorizationNotification, object: nil)
//            lastAuthorizationStatus = newStatus
//            if checkAndRequestAuthorization() {
//                startLocationServices()
//            }
//        }
//    }
//    
//    /// 定位授权，每次app启动都会回调一次
//    func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) {
//        let newStatus = status
//        if newStatus != lastAuthorizationStatus {
//            NotificationCenter.default.post(name: LocationManager3.didChangeAuthorizationNotification, object: nil)
//            lastAuthorizationStatus = newStatus
//            if checkAndRequestAuthorization() {
//                startLocationServices()
//            }
//        }
//    }
//    
//}
//
//// MARK: - Helper
//extension LocationManager3 {
//    
//    enum UserActivityType {
//        case unknown
//        case stationary
//        case walking
//        case running
//        case cycling
//        case automotive
//        case highSpeed
//        
//        var toCLActivityType: CLActivityType {
//            switch self {
//            case .unknown, .stationary, .highSpeed:
//                return .other
//            case .walking, .running, .cycling:
//                return .fitness
//            case .automotive:
//                return .automotiveNavigation
//            }
//        }
//    }
//    
//    private func calculateUserActivityAndAppropriateUpdateDistance(location: CLLocation, lastLocation: CLLocation?, completion: @escaping ((UserActivityType, CLLocationDistance) -> Void)) {
//        if CMMotionActivityManager.isActivityAvailable() && CMMotionActivityManager.authorizationStatus() == .authorized {
//            activityManager.startActivityUpdates(to: .main) { activity in
//                var userActivityType: UserActivityType = .unknown
//                var distance = 50.0
//                if activity?.stationary == true {
//                    userActivityType = .stationary
//                } else if activity?.walking == true {
//                    userActivityType = .walking
//                } else if activity?.running == true {
//                    userActivityType = .running
//                    distance = 60
//                } else if activity?.cycling == true {
//                    userActivityType = .cycling
//                    distance = 80
//                } else if activity?.automotive == true {
//                    userActivityType = .automotive
//                    distance = 150
//                } else {
//                    userActivityType = self.calculateUserActivity(location: location, lastLocation: lastLocation)
//                    distance = self.calculateUpdateDistance(location: location, lastLocation: lastLocation)
//                }
//                self.activityManager.stopActivityUpdates()
//                completion(userActivityType, distance)
//            }
//        } else {
//            let userActivityType = calculateUserActivity(location: location, lastLocation: lastLocation)
//            let distance = calculateUpdateDistance(location: location, lastLocation: lastLocation)
//            completion(userActivityType, distance)
//        }
//    }
//    
//    /// 根据速度计算用户运动类型
//    private func calculateUserActivity(location: CLLocation, lastLocation: CLLocation?) -> UserActivityType {
//        guard let lastLocation = lastLocation else { return .unknown }
//        let distance = location.distance(from: lastLocation)
//        let time = abs(location.timestamp.timeIntervalSince(lastLocation.timestamp))
//        let speed = distance / time
//        let activity: UserActivityType
//        if speed < 0.2 { // 静止
//            activity = .stationary
//        } else if speed < 2 { // 人正常走路
//            activity = .walking
//        } else if speed < 3 { // 跑步
//            activity = .running
//        } else if speed < 5 { // 自行车
//            activity = .cycling
//        } else if speed < 10 { // 电动车，摩托车，公交
//            activity = .automotive
//        } else if speed < 40 { // 汽车
//            activity = .automotive
//        } else {
//            activity = .highSpeed // 超高速
//        }
//        return activity
//    }
//    
//    /// 根据移动速度来计算地理围栏的半径
//    private func calculateUpdateDistance(location: CLLocation, lastLocation: CLLocation?) -> CLLocationDistance {
//        guard let lastLocation = lastLocation else { return 50 }
//        let distance = location.distance(from: lastLocation)
//        let time = abs(location.timestamp.timeIntervalSince(lastLocation.timestamp))
//        let speed = distance / time // m/s
//        let res: CLLocationDistance
//        
//        if speed < 0.2 { // 静止
//            res = 50
//        } else if speed < 2 { // 人正常走路
//            res = 50
//        } else if speed < 3 { // 跑步
//            res = 60
//        } else if speed < 5 { // 自行车
//            res = 80
//        } else if speed < 10 { // 电动车，摩托车，公交
//            res = 150
//        } else if speed < 40 { // 汽车
//            res = 150
//        } else {
//            res = 500 // 超高速
//        }
//        return res
//    }
//    
//}
